# 聚合上提张力计算
import math
from typing import List


from common.params import SoftParams
from strain.strain_common import AxialForceResult, data_init, UniForceResult
from model.soft.fluid_resistance import tool_pull_fluid, tool_push_fluid, cable_push_fluid, cable_pull_fluid
from model.soft.atmospheric_pressure import get_instrument_up, get_instrument_down, get_cable, get_delta_leff
from model.soft.tool_fluid import get_tool_total_force
from model.soft.cable_fluid import get_cable_total_force

# 计算张力和弱点的时候 在内部计算轴力的过程中加入其他类型的流体阻力，仪器液体阻力均除以L1，正常上提下放的电缆液体阻力是除以D-L1的 ，但是弱点是除以D
# 在内部计算过程中也要知道是否加入液体阻力
# 计算张力和弱点整体计算完成之后再额外加或者减去带有速度的流体阻力 但是考虑速度的流体阻力不影响轴力
# 内部其他+外部速度
# 原有张力计算完成之后要加或者减去井口摩擦力
# 计算 f 最新方法
def calc_f_pull(D: float, params: SoftParams, cur: AxialForceResult, pre: AxialForceResult, preN: float,
                preF: float, is_Not_add_resistance: bool) -> float:
    factor_b: float = math.cos(math.radians(pre.inclination))
    # 测井仪器的单位浮重
    w1: float = params.w1
    # 电缆的单位浮重
    w2: float = params.w2
    params.L1 = round(params.L1)
    tool_fluid: float = get_tool_total_force(params) / params.L1
    cable_fluid: float = get_cable_total_force(params) / (params.L_oh - params.L1)
    # 定义 f
    f: float = 0.0
    if is_Not_add_resistance == True:
        if (cur.depth >= D - params.L1) and (cur.depth < D):
            f = w1 * factor_b + params.get_mu_pull(cur.depth) * preN + preF - tool_fluid
            # print("{} 深度 F 计算结果为:{}".format(cur.depth,f))
        elif (cur.depth >= 0) and (cur.depth < D - params.L1):
            f = w2 * factor_b + params.get_mu_pull(cur.depth) * preN + preF - cable_fluid
            # print("{} 深度 F 计算结果为:{}".format(cur.depth,f))
    else:
        if (cur.depth >= D - params.L1) and (cur.depth < D):
            f = w1 * factor_b + params.get_mu_pull(cur.depth) * preN + preF
            # print("{} 深度 F 计算结果为:{}".format(cur.depth,f))
        elif (cur.depth >= 0) and (cur.depth < D - params.L1):
            f = w2 * factor_b + params.get_mu_pull(cur.depth) * preN + preF
            # print("{} 深度 F 计算结果为:{}".format(cur.depth,f))
    return f


# 计算 f 下放
def calc_f_push(D: float, params: SoftParams, cur: AxialForceResult, pre: AxialForceResult, preN: float,
                preF: float, is_Not_add_resistance: bool) -> float:
    factor_b: float = math.cos(math.radians(pre.inclination))
    # 测井仪器的单位浮重
    w1: float = params.w1
    # 电缆的单位浮重
    w2: float = params.w2
    params.L1 = round(params.L1)
    tool_fluid: float = get_tool_total_force(params) / params.L1
    cable_fluid: float = get_cable_total_force(params) / (params.L_oh - params.L1)
    # 定义f
    f: float = 0.0
    if is_Not_add_resistance == True:
        if (cur.depth >= D - params.L1) and (cur.depth < D):
            f: float = w1 * factor_b - params.get_mu_push(cur.depth) * preN + preF - tool_fluid
        elif (cur.depth >= 0) and (cur.depth < D - params.L1):
            f: float = w2 * factor_b - params.get_mu_push(cur.depth) * preN + preF - cable_fluid
    else:
        if (cur.depth >= D - params.L1) and (cur.depth < D):
            f: float = w1 * factor_b - params.get_mu_push(cur.depth) * preN + preF
        elif (cur.depth >= 0) and (cur.depth < D - params.L1):
            f: float = w2 * factor_b - params.get_mu_push(cur.depth) * preN + preF
    return f


# 计算 N 最新计算方法
def calc_n_pull(D: float, params: SoftParams, cur: AxialForceResult, F: float) -> float:
    # 测井仪器的单位浮重
    w1: float = params.w1
    # 电缆的单位浮重
    w2: float = params.w2
    params.L1 = round(params.L1)
    factor_a: float = cur.azimuth_rate
    factor_b: float = math.sin(math.radians(cur.inclination))
    factor_c: float = cur.inclination_rate
    if (cur.depth > D - params.L1) and (cur.depth <= D):
        factor_d: float = F * factor_a * factor_b
        factor_e: float = F * factor_c
        n: float = math.sqrt(math.pow(factor_d, 2) + math.pow(factor_e + w1 * factor_b, 2))
        # print("{} 深度 N 计算结果为:{}".format(cur.depth,n))
        return n
    elif (cur.depth >= 0) and (cur.depth <= D - params.L1):
        factor_d: float = F * factor_a * factor_b
        factor_e: float = F * factor_c
        n: float = math.sqrt(math.pow(factor_d, 2) + math.pow(factor_e + w2 * factor_b, 2))
        # print("{} 深度 N 计算结果为:{}".format(cur.depth,n))

        return n
    # return cur.N


# push 正压力计算
def calc_n_push(D: float, params: SoftParams, cur: AxialForceResult, F: float) -> float:
    # 测井仪器的单位浮重
    w1: float = params.w1
    # 电缆的单位浮重
    w2: float = params.w2
    params.L1 = round(params.L1)
    factor_a: float = cur.azimuth_rate
    factor_b: float = math.sin(math.radians(cur.inclination))
    factor_c: float = cur.inclination_rate
    if (cur.depth > D - params.L1) and (cur.depth <= D):
        factor_d: float = F * factor_a * factor_b
        factor_e: float = F * factor_c
        n: float = math.sqrt(math.pow(factor_d, 2) + math.pow(factor_e + w1 * factor_b, 2))
        # print("{} 深度 N 计算结果为:{}".format(D,n))
        return n
    elif (cur.depth >= 0) and (cur.depth <= D - params.L1):
        factor_d: float = F * factor_a * factor_b
        factor_e: float = F * factor_c
        n: float = math.sqrt(math.pow(factor_d, 2) + math.pow(factor_e + w2 * factor_b, 2))

        return n


# 计算 N 弱点拉力最新计算方法
def calc_n_weak_pull(D: float, params: SoftParams, cur: AxialForceResult, F: float) -> float:
    # 电缆的单位浮重
    w2: float = params.w2
    factor_a: float = cur.azimuth_rate
    factor_b: float = math.sin(math.radians(cur.inclination))
    factor_c: float = cur.inclination_rate
    if (cur.depth >= 0) and (cur.depth <= D):
        factor_d: float = F * factor_a * factor_b
        factor_e: float = F * factor_c
        n: float = math.sqrt(math.pow(factor_d, 2) + math.pow(factor_e + w2 * factor_b, 2))
        return n
    # return cur.N


# 计算 f_weak_ 最新方法
def calc_f_weak_pull(D: float, params: SoftParams, cur: AxialForceResult, pre: AxialForceResult, preN: float,
                preF: float, is_Not_add_resistance: bool) -> float:
    factor_b: float = math.cos(math.radians(pre.inclination))
    # 电缆的单位浮重
    w2: float = params.w2
    cable_fluid: float = get_cable_total_force(params) / params.L_oh
    if is_Not_add_resistance == True:
        if (cur.depth >= 0) and (cur.depth <= D):
            f: float = w2 * factor_b + params.get_mu_pull(cur.depth) * preN + preF - cable_fluid
            return f
    else:
        if (cur.depth >= 0) and (cur.depth <= D):
            f: float = w2 * factor_b + params.get_mu_pull(cur.depth) * preN + preF
            return f


# 最新版的计算变形量
def calc_pull_strain(D: float, params: SoftParams, cur: AxialForceResult, F: float) -> float:

    if cur.depth == D:
        return 0.0
    if (cur.depth >= D - params.L1) and (cur.depth < D):
        pull_strain: float = 0.0
        return pull_strain
    elif (cur.depth >= 0.0) and (cur.depth < D - params.L1):
        pull_strain: float = F / (params.E2 * params.A2)
        return pull_strain


def calc_push_strain(D: float, params: SoftParams, cur: AxialForceResult, F: float) -> float:
    if cur.depth == D:
        return 0.0
    if (cur.depth >= D - params.L1) and (cur.depth < D):
        push_strain: float = 0.0
        return push_strain
    elif (cur.depth >= 0.0) and (cur.depth < D - params.L1):
        push_strain: float = F / (params.E2 * params.A2)
        return push_strain


def calc_uni(D: float, params: SoftParams, cur: AxialForceResult, pre: AxialForceResult,
             _list_: List[AxialForceResult], is_Not_add_resistance: bool) -> AxialForceResult:
    # 几种类型的点
    cur.F_push = calc_f_push(D, params, cur, pre, pre.N_push, pre.F_push, is_Not_add_resistance)
    cur.N_push = calc_n_push(D, params, cur, cur.F_push)

    cur.F_pull = calc_f_pull(D, params, cur, pre, pre.N_pull, pre.F_pull, is_Not_add_resistance)
    cur.N_pull = calc_n_pull(D, params, cur, cur.F_pull)

    cur.strain_push = calc_push_strain(D, params, cur, cur.F_push)
    cur.strain_pull = calc_pull_strain(D, params, cur, cur.F_pull)

    # 弱点的计算都是用上提的计算 ---> + 2 函数 calc_f_weak_pull  calc_n_weak_pull
    cur.F_weak_low = calc_f_weak_pull(D, params, cur, pre, pre.N_weak_low, pre.F_weak_low, is_Not_add_resistance)
    cur.N_weak_low = calc_n_weak_pull(D, params, cur, cur.F_weak_low)

    cur.F_weak_high = calc_f_weak_pull(D, params, cur, pre, pre.N_weak_high, pre.F_weak_high, is_Not_add_resistance)
    cur.N_weak_high = calc_n_weak_pull(D, params, cur, cur.F_weak_high)

    cur.F_weak_rate_low = calc_f_weak_pull(D, params, cur, pre, pre.N_weak_rate_low, pre.F_weak_rate_low, is_Not_add_resistance)
    cur.N_weak_rate_low = calc_n_weak_pull(D, params, cur, cur.F_weak_rate_low)

    # print(JsonUtil.obj2str(cur))
    return cur


# 迭代函数
def deep_func(idx: int, params: SoftParams, _list_: List[AxialForceResult], fluid_resistances_pull: dict, fluid_resistances_push: dict, weak_fluid_resistances_pull: dict, is_Not_add_resistance: bool, wellhead_friction: float) -> UniForceResult:
    # 本次迭代深度
    D: float = _list_[idx].depth


    # 5种类型的点
    _list_[idx].F_push = 0.0
    _list_[idx].N_push = calc_n_push(D, params, _list_[idx], _list_[idx].F_push)

    _list_[idx].F_pull = 0.0
    _list_[idx].N_pull = calc_n_pull(D, params, _list_[idx], _list_[idx].F_pull)

    _list_[idx].strain_push = calc_push_strain(D, params, _list_[idx], _list_[idx].F_push)
    _list_[idx].strain_pull = calc_pull_strain(D, params, _list_[idx], _list_[idx].F_pull)

    _list_[idx].F_weak_low = params.F_weak_low
    _list_[idx].N_weak_low = calc_n_weak_pull(D, params, _list_[idx], _list_[idx].F_weak_low)

    _list_[idx].F_weak_high = params.F_weak_high
    _list_[idx].N_weak_high = calc_n_weak_pull(D, params, _list_[idx], _list_[idx].F_weak_high)

    _list_[idx].F_weak_rate_low = params.F_weak_rate_low
    _list_[idx].N_weak_rate_low = calc_n_weak_pull(D, params, _list_[idx], _list_[idx].F_weak_rate_low)
    leff: float = get_delta_leff(params) * (_list_[idx].depth - params.L1)

    result: UniForceResult = UniForceResult()
    all_strain_pull: float = 0.0
    all_strain_push: float = 0.0
    # f_push_hel_depth: float = 0.0
    # f_pull_hel_depth: float = 0.0
    # leff: float = 0.0
    compress_push = 0
    compress_pull = 0
    # 发生螺旋深度
    # hel_depth: float = 0.0
    for i in range(idx - 1, -1, -1):

        _list_[i] = calc_uni(_list_[idx].depth, params, _list_[i], _list_[i + 1], _list_, is_Not_add_resistance)

        result.depth = D
        if is_Not_add_resistance == True:
            result.F_pull = _list_[i].F_pull + fluid_resistances_pull[D] + wellhead_friction + get_instrument_up(params) - get_instrument_down(params)
            result.F_push = _list_[i].F_push - fluid_resistances_push[D] - wellhead_friction + get_instrument_up(params) - get_instrument_down(params)
            result.F_weak_low = _list_[i].F_weak_low + weak_fluid_resistances_pull[D] + wellhead_friction - get_cable(params)
            result.F_weak_high = _list_[i].F_weak_high + weak_fluid_resistances_pull[D] + wellhead_friction - get_cable(params)
            result.F_weak_rate_low = _list_[i].F_weak_rate_low + weak_fluid_resistances_pull[D] + wellhead_friction - get_cable(params)
            # 下述注释代码为测试最初的张力和弱点（带有速度的液体阻力，不包含井口摩擦力和大气压力）
            # result.F_pull = _list_[i].F_pull + fluid_resistances_pull[D]
            # result.F_push = _list_[i].F_push - fluid_resistances_push[D]
            # result.F_weak_low = _list_[i].F_weak_low + weak_fluid_resistances_pull[D]
            # result.F_weak_high = _list_[i].F_weak_high + weak_fluid_resistances_pull[D]
            # result.F_weak_rate_low = _list_[i].F_weak_rate_low + weak_fluid_resistances_pull[D]

        else:
            result.F_pull = _list_[i].F_pull + wellhead_friction + get_instrument_up(params) - get_instrument_down(params)
            result.F_push = _list_[i].F_push - wellhead_friction + get_instrument_up(params) - get_instrument_down(params)
            result.F_weak_low = _list_[i].F_weak_low + wellhead_friction - get_cable(params)
            result.F_weak_high = _list_[i].F_weak_high + wellhead_friction - get_cable(params)
            result.F_weak_rate_low = _list_[i].F_weak_rate_low + wellhead_friction - get_cable(params)
            # 下述注释代码为测试最初的张力和弱点（最原始的张力和弱点，没有带有速度的液体阻力、井口摩擦力和大气压力）
            # result.F_pull = _list_[i].F_pull
            # result.F_push = _list_[i].F_push
            # result.F_weak_low = _list_[i].F_weak_low
            # result.F_weak_high = _list_[i].F_weak_high
            # result.F_weak_rate_low = _list_[i].F_weak_rate_low

        result.N_pull = _list_[i].N_pull
        result.N_push = _list_[i].N_push
        result.N_weak_low = _list_[i].N_weak_low
        result.N_weak_high = _list_[i].N_weak_high
        result.N_weak_rate_low = _list_[i].N_weak_rate_low
        result.strain_pull = _list_[i].strain_pull
        result.strain_push = _list_[i].strain_push
        all_strain_push = all_strain_push + _list_[i].strain_push
        all_strain_pull = all_strain_pull + _list_[i].strain_pull

        if all_strain_push + leff < 0.0:
            result.all_strain_push = round(all_strain_push, 2)
        else:
            result.all_strain_push = round(all_strain_push + leff, 2)
        if all_strain_pull + leff < 0.0:
            result.all_strain_pull = round(all_strain_pull, 2)
        else:
            result.all_strain_pull = round(all_strain_pull + leff, 2)


        result.compress_pull = 0
        result.compress_push = 0
        # f_push_hel_depth: float = 0.0
        # 获取临界螺旋屈曲的点
        # 这是原来设置屈曲载荷的位置
        # f_hel = params.get_f_hel(int(_list_[i].depth))

        # 如果轴力小于0 并且存在屈曲载荷 标记对应的点 如果没过输出-1
        # 原来该位置都使用result.F_push 和result.F_pull 现在由于加上液体阻力 进行修正 改为_list_[i].F_push和_list_[i].F_pull
        if _list_[i].F_push < 0.0:
            compress_push = 1
            # print("下放存在压缩")
            # if math.fabs(_list_[i].F_push) > f_hel:
            #     f_push_hel_depth = _list_[i].depth
        if _list_[i].F_pull < 0.0:
            compress_pull = 1
            # print("上提存在压缩")
            # if math.fabs(_list_[i].F_pull) > f_hel:
            #     f_pull_hel_depth = _list_[i].depth

        if _list_[i].depth <= 0:

            result.N_pull = _list_[i+1].N_pull
            result.N_push = _list_[i+1].N_push
            result.N_weak_low = _list_[i + 1].N_weak_low
            result.N_weak_high = _list_[i + 1].N_weak_high
            result.N_weak_rate_low = _list_[i + 1].N_weak_rate_low
            if all_strain_push + leff < 0.0:
                result.all_strain_push = round(all_strain_push, 2)
            else:
                result.all_strain_push = round(all_strain_push + leff, 2)
            if all_strain_pull + leff < 0.0:
                result.all_strain_pull = round(all_strain_pull, 2)
            else:
                result.all_strain_pull = round(all_strain_pull + leff, 2)
            # result.f_pull_hel_depth = f_pull_hel_depth
            # result.f_push_hel_depth = f_push_hel_depth
            result.compress_push = compress_push
            result.compress_pull = compress_pull
            # result.hel_depth = hel_depth
            # print(JsonUtil.obj2str(result))
            return result


# 聚合构建 返回计算结果
def uni_build(params: SoftParams, _list_: List[AxialForceResult], is_Not_add_resistance: bool, desired_depths: List[float], wellhead_friction: float) -> List[UniForceResult]:
    D: float = _list_[-1].depth
    # T 为张力
    t: List[UniForceResult] = []
    data_len = len(_list_)
    params.L1 = round(params.L1)
    # 计算正常上提和下放所有深度点的液体阻力
    fluid_resistances_pull = {}
    fluid_resistances_push = {}
    # 计算弱点的所有深度的液体阻力 只有上提过程中的电缆液体阻力
    weak_fluid_resistances_pull = {}
    for idx in range(data_len):
        fluid_resistances_pull[_list_[idx].depth] = tool_pull_fluid(params, _list_[idx]) + cable_pull_fluid(params,_list_[idx])
        fluid_resistances_push[_list_[idx].depth] = tool_push_fluid(params, _list_[idx]) + cable_push_fluid(params,_list_[idx])
        weak_fluid_resistances_pull[_list_[idx].depth] = cable_pull_fluid(params, _list_[idx])
        # fluid_resistances_pull[_list_[idx].depth] = tool_pull_fluid(params, _list_[idx]) + cable_pull_fluid(params, _list_[idx]) - get_tool_total_force(params) - get_cable_total_force(params, _list_[idx])
        # fluid_resistances_push[_list_[idx].depth] = tool_push_fluid(params, _list_[idx]) + cable_push_fluid(params, _list_[idx]) + get_tool_total_force(params) + get_cable_total_force(params, _list_[idx])
        # weak_fluid_resistances_pull[_list_[idx].depth] = cable_pull_fluid(params, _list_[idx]) - get_cable_total_force(params, _list_[idx])

    # 设置迭代次数 判断当前深度是不是在间隔的列表里 如果在间隔列表里才进行迭代计算 否则不计算
    for depth in desired_depths:
        # 找到对应深度在 _list_ 中的索引
        idx = next((i for i, item in enumerate(_list_) if item.depth >= depth), None)
        if idx is not None and idx >= params.L1:
            # print("==========={}==============".format(idx))
            # print("从深度{}开始迭代".format(_list_[idx].depth))
            t_item: UniForceResult = deep_func(idx, params, _list_, fluid_resistances_pull, fluid_resistances_push, weak_fluid_resistances_pull, is_Not_add_resistance, wellhead_friction)
            # print(JsonUtil.obj2str(t_item))
            t.append(t_item)
    return t


# 参数 list [OilWellData]
def run(params: SoftParams, _list_, is_Not_add_resistance: bool, desired_depths: List[float], wellhead_friction: float) -> List[UniForceResult]:
    # 数据预处理
    result_arr: List[AxialForceResult] = data_init(_list_)
    # 计算结果
    result: List[UniForceResult] = uni_build(params, result_arr, is_Not_add_resistance, desired_depths, wellhead_friction)

    return result
